/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ontoTree.ontoTree;

// Alignment API classes
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.semanticweb.owl.align.Alignment;
import org.semanticweb.owl.align.AlignmentException;
import org.semanticweb.owl.align.AlignmentProcess;
import org.semanticweb.owl.align.AlignmentVisitor;
import org.semanticweb.owl.align.Parameters;

import fr.inrialpes.exmo.align.impl.BasicParameters;
import fr.inrialpes.exmo.align.parser.AlignmentParser;
import fr.inrialpes.exmo.align.impl.method.StringDistAlignment;
import fr.inrialpes.exmo.align.impl.renderer.RDFRendererVisitor;
// SAX standard classes
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.util.Enumeration;
import java.util.HashMap;

import org.semanticweb.owl.align.Cell;
import org.semanticweb.owl.align.Relation;
import fr.inrialpes.exmo.align.impl.rel.EquivRelation;
import fr.inrialpes.exmo.align.impl.rel.SubsumedRelation;
import fr.inrialpes.exmo.align.impl.rel.SubsumeRelation;
import fr.inrialpes.exmo.align.impl.rel.IncompatRelation;


import java.util.ArrayList;
import java.util.Iterator;
import org.omwg.mediation.parser.rdf.RDFParserException;
import org.semanticweb.owl.align.AlignmentException;
import org.xml.sax.SAXException;


/**
 * Classes para aprender a manipular um alinhamento
 * @author Fabiana Freire & Fernanda LÍgia
 */
public class AlignManagement {

    private HashMap<String, ArrayList> aResult, bResult;
        
    void align(URI ontology1, URI ontology2, String method) {

        //Parâmetro para alinhamento
	Parameters params = new BasicParameters();
                    
        try {
            // Aligning
            AlignmentProcess a1 = new StringDistAlignment();
            params.setParameter("stringFunction",method);    
            a1.init ( ontology1, ontology2 );
            a1.align( (Alignment)null, params );
        } catch (AlignmentException ae) {
            System.out.print("Erro ao tentar alinhar no método alinha(): \n");
            ae.printStackTrace();
        } 
        
    }
    public Alignment openAlignmentFile(String alignpath) {
        
        Alignment a = null;
        
        try {
            AlignmentParser ap = new AlignmentParser(1);
            a = ap.parse(alignpath);
        }catch (ParserConfigurationException pce) {
            System.out.println("Error Parser Configuration");
        } catch (RDFParserException rdf) {
            System.out.println("Error Parser Configuration");
        }catch (SAXException se) {
            System.out.println("Erro na leitura (SAXException)");
            se.printStackTrace();
        }catch (IOException io){
            System.out.println("Problema para encontrar arquivo (IOException");
        }    
        
        return a;
    }
     public void store(Alignment alignment){
        
        aResult = new HashMap<String, ArrayList>();
        bResult = new HashMap<String, ArrayList>();
        
        try {
            
            for (Enumeration e = alignment.getElements(); e.hasMoreElements();) {

                    Cell c = (Cell) e.nextElement();

                    String uri1 = c.getObject1AsURI(alignment).toString();
                    String uri2 = c.getObject2AsURI(alignment).toString();
                    String rel = relationToString(c.getRelation());
                    double simi = c.getStrength();

                    Mapping a = new Mapping();
                    a.setUri1(uri1);
                    a.setUri2(uri2);
                    a.setRelation(rel);
                    a.setSimi(simi);

                    ArrayList<Mapping> list = (ArrayList)aResult.get(uri1);
                    if (list == null){
                        list = new ArrayList<Mapping>();
                        list.add(a);
                        aResult.put(uri1, list);
                    } else {
                        list.add(a);
                        aResult.put(uri1, list);

                    }
                    
                    ArrayList<String> listb = (ArrayList)bResult.get(uri2);
                    if (listb == null){
                        listb = new ArrayList<String>();
                        listb.add(uri1);
                        bResult.put(uri2, listb);
                    } else {
                        listb.add(uri1);
                        bResult.put(uri2, listb);
                    }

            }
        } catch (AlignmentException e1) {
            e1.printStackTrace();
	}
    
    }
//    public void store(Alignment alignment){
//        
//        aResult = new HashMap<String, Object>();
//        bResult = new HashMap<String, Object>();
//        
//        try {
//            
//            for (Enumeration e = alignment.getElements(); e.hasMoreElements();) {
//
//                    Cell c = (Cell) e.nextElement();
//
//                    String uri1 = c.getObject1AsURI(alignment).toString();
//                    String uri2 = c.getObject2AsURI(alignment).toString();
//                    String rel = relationToString(c.getRelation());
//                    double simi = c.getStrength();
//
//                    Mapping a = new Mapping();
//                    a.setUri1(uri1);
//                    a.setUri2(uri2);
//                    a.setRelation(rel);
//                    a.setSimi(simi);
//
//                    Object obja = aResult.get(uri1);
//                    if (obja == null){
//                        aResult.put(uri1, a);
//                    } else if (obja instanceof ArrayList){
//                        ((ArrayList)obja).add(a);
//                    } else if (obja instanceof Mapping){
//                        ArrayList list = new ArrayList();
//                        list.add(obja);
//                        list.add(a);
//                        aResult.put(uri1, list);
//
//                    }
//                    
//                    Object objb = bResult.get(uri2);
//                    if (objb == null){
//                        bResult.put(uri2, uri1);
//                    } else if (objb instanceof ArrayList){
//                        ArrayList list = (ArrayList)objb;
//                        list.add(uri1);
//                        bResult.put(uri2, list);
//                    } else {
//                        ArrayList list = new ArrayList();
//                        list.add(objb);
//                        list.add(uri1);
//                        bResult.put(uri2, list);
//                    }
//
//            }
//            //printHashAResults(aResult);
//            //printHashBResults(bResult);
//        } catch (AlignmentException e1) {
//            e1.printStackTrace();
//	}
//    
//    }
    public HashMap<String, ArrayList> store(Alignment alignment, boolean order){
        
        HashMap<String, ArrayList> result = new HashMap<String, ArrayList>();
        String key = "";
        
        try {
            
            for (Enumeration e = alignment.getElements(); e.hasMoreElements();) {

                    Cell c = (Cell) e.nextElement();

                    String uri1 = c.getObject1AsURI(alignment).toString();
                    String uri2 = c.getObject2AsURI(alignment).toString();
                    String rel = relationToString(c.getRelation());
                    double simi = c.getStrength();

                    Mapping a = new Mapping();
                    ArrayList obja = null;
                    if (order){
                        key = uri2.substring(uri2.indexOf("#"), uri2.length());
                        obja = result.get(key);
                        a.setUri1(uri1);
                        a.setUri2(uri2);
                        a.setRelation(rel);
                        a.setSimi(simi);
                    } else {
                        key = uri1.substring(uri1.indexOf("#"), uri1.length());;
                        obja = result.get(key);
                        a.setUri1(uri2);
                        a.setUri2(uri1);
                        if (rel.equals("&lt;")) {
                            rel = "&gt;"; //"SubsumedRelation (>)";
                        } else if (rel.equals("&gt;")) {
                            rel = "&lt;";//"SubsumeRelation (<)";
                        } 
                        a.setRelation(rel);
                        a.setSimi(simi);
                    }
                    
                    if (obja == null){
                        obja = new ArrayList<Mapping>();
                        obja.add(a);
                    } else {
                        obja.add(a);
                    }
                        
                    result.put(key, obja);
 
            }
            
        } catch (AlignmentException e1) {
            e1.printStackTrace();
	}
        return result;
    
    }
//    public void store(Alignment alignment, int direction){
//        
//        aResult = new HashMap<String, Object>();
//        bResult = new HashMap<String, Object>();
//        try {
//
//            for (Enumeration e = alignment.getElements(); e.hasMoreElements();) {
//
//                    Cell c = (Cell) e.nextElement();
//
//                    String uri1 = c.getObject1AsURI(alignment).toString();
//                    String uri2 = c.getObject2AsURI(alignment).toString();
//                    String rel = relationToString(c.getRelation());
//                    Double simi = c.getStrength();
//
//                    Mapping a = new Mapping();
//                    a.setUri1(uri1);
//                    a.setUri2(uri2);
//                    a.setRelation(rel);
//                    a.setSimi(simi);
//
//                    aResult.put(uri1, a);
//                    bResult.put(uri2, uri1);
//
//            }
//            
//        } catch (AlignmentException e1) {
//            e1.printStackTrace();
//	}
//    
//    }
    public HashMap<String,ArrayList> getAResult(){
        return aResult;
    }
    public HashMap<String,ArrayList> getBResult(){
        return bResult;
    }
    /*
     * Calc Global similarity using DICE: (|M12|+ |M21|) /(|O1|+|O2|) Where:
     *  --> |M12| is all correspondences in direction O1 to O2
     *  --> |M21| is all correspondences in direction O2 to O1
     *  --> |O1| is all elements of the ontology O1 (classe + properties)
     *  --> |O2| is all elements of the ontology O2 (classe + properties)
     */
    public double globalSimilarity(HashMap<String, ArrayList> aResult, OntModel onto1, OntModel onto2) {
        //Fórmula DICE
        //Total concepts in O1
        ExtendedIterator ic1 = onto1.listNamedClasses();
        int sizeO1 = ic1.toList().size();
        ExtendedIterator ipDT1 = onto1.listDatatypeProperties();
        sizeO1 += ipDT1.toList().size();
        ExtendedIterator ipObj1 = onto1.listObjectProperties();
        sizeO1 += ipObj1.toList().size();
        //Total concepts in O2
        ExtendedIterator ic2 = onto2.listNamedClasses();
        int sizeO2 = ic2.toList().size();
        ExtendedIterator ipDT2 = onto2.listDatatypeProperties();
        sizeO2 += ipDT2.toList().size();
        ExtendedIterator ipObj2 = onto2.listObjectProperties();
        sizeO2 += ipObj2.toList().size();
        //Total correspondecesn in alignment
        Set<String> en = aResult.keySet();
        Iterator it = en.iterator();
        int sizeO1O2 = 0; 
        for (int i = 0 ; i < en.size(); i++){
           String key = (String) it.next();
           ArrayList tmp = aResult.get (key);
           for (int j = 0;j<tmp.size();j++){
                sizeO1O2++;
           }
        }
        double globalsimilarity = (double)  (2*sizeO1O2) / (sizeO1 + sizeO2);

        return globalsimilarity;
    }
    
    public void printHashBResults(HashMap<String, Object> bResult) {
        
         Set<String> en = bResult.keySet();
         Iterator it = en.iterator();

         for (int i=0;i<en.size();i++)
         {
            String key = (String) it.next();
            System.out.println ("\nKEY: "  + key);
            Object obj = bResult.get (key);
            if (obj instanceof ArrayList){
                ArrayList list = (ArrayList)obj;
                for (int j=0;j<list.size();j++){
                    String map = (String)list.get(j);
                    System.out.println ("-URI1: "  + map);
                }
            } else {
                String map = obj.toString();
                System.out.println ("+URI1: "  + map);
            }
            
         }

    }
    public void printAResults(HashMap<String, ArrayList> aResult) {
        
         Set<String> en = aResult.keySet();
         Iterator it = en.iterator();

         for (int i=0;i<en.size();i++){
            String key = (String) it.next();
            System.out.println ("\nKEY: "  + key);
            ArrayList list = aResult.get (key);
            for (int j=0;j<list.size();j++){
                 Mapping map = (Mapping)list.get(j);
                 System.out.println ("-URI1: "  + map.getUri1());
                 System.out.println ("-URI2: "  + map.getUri2());
                 System.out.println ("-Relation: "  + map.getRelation());
                 System.out.println ("-Similarity: "  + map.getSimi() + "\n");
            }            
         }

    }
     public void printHashAResults(HashMap<String, Object> aResult) {
        
         Set<String> en = aResult.keySet();
         Iterator it = en.iterator();

         for (int i=0;i<en.size();i++)
         {
            String key = (String) it.next();
            System.out.println ("\nKEY: "  + key);
            Object obj = aResult.get (key);
            if (obj instanceof ArrayList){
                ArrayList list = (ArrayList)obj;
                for (int j=0;j<list.size();j++){
                    Mapping map = (Mapping)list.get(j);
                    System.out.println ("-URI1: "  + map.getUri1());
                    System.out.println ("-URI2: "  + map.getUri2());
                    System.out.println ("-Relation: "  + map.getRelation());
                    System.out.println ("-Similarity: "  + map.getSimi() + "\n");
                }
            } else if (obj instanceof Mapping){
                Mapping map = (Mapping)obj;
                System.out.println ("+URI1: "  + map.getUri1());
                System.out.println ("+URI2: "  + map.getUri2());
                System.out.println ("+Relation: "  + map.getRelation());
                System.out.println ("+Similarity: "  + map.getSimi() + "\n");
            }
            
         }

    }
//     public void printHashResults(HashMap<String, String> bResult) {
//        
//         System.out.println ("\n#####################################");
//         Set<String> en = bResult.keySet();
//         Iterator it = en.iterator();
//
//         for (int i=0;i<en.size();i++)
//         {
//            String key = (String) it.next();
//            System.out.println ("\nKEY: "  + key);
//            String map =  bResult.get (key);
//            System.out.println ("mapA: "  + map);
//         }
//
//    }
     
//    public void printHashResults(HashMap<String, Mapping> aResult) {
//        
//         Set<String> en = aResult.keySet();
//         Iterator it = en.iterator();
//
//         for (int i=0;i<en.size();i++)
//         {
//            String key = (String) it.next();
//            System.out.println ("\nKEY: "  + key);
//            Mapping map =  aResult.get (key);
//            System.out.println ("URI1: "  + map.getUri1());
//            System.out.println ("URI2: "  + map.getUri2());
//            System.out.println ("Relation: "  + map.getRelation());
//            System.out.println ("Similarity: "  + map.getSimi() + "\n");
//         }
//
//    }
    
    public void printCell(Mapping map) {
        System.out.println("URI1: " + map.getUri1());
        System.out.println("URI2: " + map.getUri2());
        System.out.println("Similarity: " + map.getSimi());
        System.out.println("Relation: " + map.getRelation());
    }
              
    public String relationToString(Relation rel) {
        String relation = null;

        try {
                if ((rel instanceof EquivRelation))  {
                    relation = "=";
                } else if (rel instanceof SubsumeRelation) {
                    // replace("<",&lt;) --> Subclass
                    relation = "&lt;"; //"SubsumedRelation";
                } else if (rel instanceof SubsumedRelation) {
                    // replace(">",&gt;) --> Superclass
                    relation = "&gt;";//"SubsumeRelation";
                } else if (rel instanceof IncompatRelation) {
                    relation = "IncompatRelation";
                } 

        } catch (Exception e) {
                e.printStackTrace();
        }

        return relation;
    }
    
    public void printAlignment(Alignment a) {
        try {
            // Outputing
            PrintWriter writer = new PrintWriter (
                                  new BufferedWriter(
                                   new OutputStreamWriter( System.out, "UTF-8" )), true);
            AlignmentVisitor renderer = new RDFRendererVisitor(writer);
            a.render(renderer);
            writer.flush();
            writer.close();    
        
        } 
        catch (AlignmentException ae) {
            System.out.print("Erro ao tentar alinhar no método print(): \n");
            ae.printStackTrace();
        } 
        catch (UnsupportedEncodingException uee) {
            System.out.print("Codificação não suportada no método print(): \n");
            uee.printStackTrace();     
        } 
    }

}
